﻿using Castle.DynamicProxy;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

namespace ServiceKit.JsonRpc
{
    public class RpcServiceInterceptor : IInterceptor
    {
        private string serviceUrl = "";
        private ServerConfig serverConfig { get; set; }

        public RpcServiceInterceptor(string moduleName, string serviceName)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");
            IConfiguration config = builder.Build();
            serverConfig = config.Get<ServerConfig>();
            serviceUrl = RpcContants.RpcConfig.Template.Replace("{module}", moduleName.ToLower()).Replace("{service}", serviceName.ToLower());
        }

        public void Intercept(IInvocation invocation)
        {
            var interfaceName = invocation.Method.ReflectedType.FullName;
            var methodName = invocation.Method.Name;
            var returnType = invocation.Method.ReturnType;

            string result = string.Empty;
            try
            {
                //参数校验
                if (invocation.Arguments.Length == 0 || (invocation.Arguments.Length > 0 && invocation.Arguments.Any(x => x != null)))
                {
                    string host = serverConfig.ServerHost;
                    if (!host.EndsWith("/"))
                    {
                        host += "/";
                    }
                    var methodParams = RpcContants.RpcConfig.JsonSerializerSettings == null
                                        ? JToken.FromObject(invocation.Arguments)
                                        : JToken.FromObject(invocation.Arguments, JsonSerializer.Create(RpcContants.RpcConfig.JsonSerializerSettings));
                    var enityRequest = new RpcRequest(Guid.NewGuid().ToString(), methodName, methodParams);
                    string body = JsonConvert.SerializeObject(enityRequest, Formatting.None, RpcContants.RpcConfig.JsonSerializerSettings);
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host + serviceUrl);
                    request.Method = "post";
                    request.ContentType = "application/json";
                    var buffer = Encoding.UTF8.GetBytes(body);
                    if (buffer != null && buffer.Length > 0)
                    {
                        request.ContentLength = buffer.Length;
                        request.GetRequestStream().Write(buffer, 0, buffer.Length);
                    }
                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                    {
                        result = reader.ReadToEnd();
                        if (!string.IsNullOrEmpty(result))
                        {
                            if (null != RpcContants.RpcConfig.JsonSerializerSettings)
                            {
                                var rpcResponse = JsonConvert.DeserializeObject<RpcResponse>(result, RpcContants.RpcConfig.JsonSerializerSettings);
                                if (returnType != typeof(void))
                                {
                                    if (rpcResponse.Code == 0)
                                    {
                                        invocation.ReturnValue = rpcResponse.Result.ToObject(returnType);
                                    }
                                    else
                                    {
                                        throw new Exception(rpcResponse.Message);
                                    }
                                }
                            }
                            else
                            {
                                var rpcResponse = JsonConvert.DeserializeObject<RpcResponse>(result);
                                if (returnType != typeof(void))
                                {
                                    if (rpcResponse.Code == 0)
                                    {
                                        invocation.ReturnValue = rpcResponse.Result.ToObject(returnType);
                                    }
                                    else
                                    {
                                        throw new Exception(rpcResponse.Message);
                                    }
                                }
                            }
                        }
                        else
                        {
                            throw new Exception(methodName + "方法返回异常");
                        }
                    }
                }
                else
                {
                    throw new Exception(methodName + "参数列表为空,非法的请求");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
